﻿/*
程序说明：
1、本程序使用多线程，即UI、服务端、客户端分别在不同的线程运行。
2、线程之间使用信号-槽方式进行交互。
3、UI线定义了所有服务端与客户端信号的槽和调用服务端与客户端槽函数的信号。
4、初始设定：非安全模式通信，服务端监听所有地址。
*/

//MSVC编译器指定字符集，防止中文报错和乱码。MingW无需理会。
#if _MSC_VER >= 1600
#pragma execution_character_set("utf-8")
#endif

#include "websocketapply.h"
#include "ui_websocketapply.h"

WebSocketApply::WebSocketApply(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::WebSocketApply)
{
    ui->setupUi(this);

    ui->kick->setEnabled(false);
    ui->server_stop->setEnabled(false);
    ui->client_disconnect->setEnabled(false);
    ui->server_send->setEnabled(false);
    ui->client_send->setEnabled(false);

    ui->listen_address->addItem("127.0.0.1");
    ui->listen_port->setText("10086");
    ui->ServerUrl->setText("ws://127.0.0.1:10086");

    QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();
    for (int i = 0; i < ipAddressesList.size(); ++i)
    {
        if (ipAddressesList.at(i) != QHostAddress::LocalHost &&  ipAddressesList.at(i).toIPv4Address())
        {
            ui->listen_address->addItem(ipAddressesList.at(i).toString());
        }
    }

    wsclient = new WSClient;
    client_thread = new QThread;
    connect(client_thread,&QThread::finished,wsclient,&QObject::deleteLater);
    wsclient->moveToThread(client_thread);
    connect(wsclient,&WSClient::connection_state,this,&WebSocketApply::C_connection);
    connect(wsclient,&WSClient::occur_error,this,&WebSocketApply::C_error);
    connect(wsclient,&WSClient::NewTextMessage,this,&WebSocketApply::C_recive);
    connect(wsclient,&WSClient::NewBinaryMessage,this,&WebSocketApply::C_reciveBinary);

    connect(this, &WebSocketApply::C_connect, wsclient, &WSClient::ConnectTo);
    connect(this, &WebSocketApply::C_disconnect, wsclient, &WSClient::Disconnect);
    connect(this, &WebSocketApply::C_sendBinary, wsclient, &WSClient::sendBinaryMessage);
    connect(this, &WebSocketApply::C_send, wsclient, &WSClient::sendTextMessage);

    client_thread->start();

    wsserver = new WSServer;
    server_thread = new QThread;
    connect(server_thread,&QThread::finished,wsserver,&QObject::deleteLater);
    wsserver->moveToThread(server_thread);
    connect(wsserver,&WSServer::NewClient_conncted,this,&WebSocketApply::add_client);
    connect(wsserver,&WSServer::Client_disconncted,this,&WebSocketApply::remove_client);
    connect(wsserver,&WSServer::NewTextMessage,this,&WebSocketApply::S_recive);
    connect(wsserver,&WSServer::NewBinaryMessage,this,&WebSocketApply::S_reciveBinary);
    connect(wsserver,&WSServer::occur_error,this,&WebSocketApply::S_error);

    connect(this,&WebSocketApply::S_start,wsserver,&WSServer::Server_start);
    connect(this,&WebSocketApply::S_stop,wsserver,&WSServer::Server_stop);
    connect(this,&WebSocketApply::S_send,wsserver,&WSServer::Server_sendmsg);
    connect(this, &WebSocketApply::S_sendBinary, wsserver, &WSServer::Server_sendBmsg);
    connect(this,&WebSocketApply::S_remove,wsserver,&WSServer::remove_client);

    server_thread->start();

    STimer = new QTimer(this);
    connect(STimer, &QTimer::timeout, [this]{
        on_server_send_clicked();
    });

    CTimer = new QTimer(this);
    connect(CTimer, &QTimer::timeout, [this]{
        on_client_send_clicked();
    });
    // QTimer::singleShot(2*60*1000, this, [=]{this->close();});//试用
}

WebSocketApply::~WebSocketApply()
{
    if(STimer->isActive())
    {
        STimer->stop();
    }
    if(CTimer->isActive())
    {
        CTimer->stop();
    }
    if(client_thread->isRunning())
    {
        client_thread->quit();
        client_thread->wait();
    }
    if(server_thread->isRunning())
    {
        server_thread->quit();
        server_thread->wait();
    }
    delete ui;
}

/* 客户端操作 begin */
void WebSocketApply::C_recive(const QString& message)
{
    QString datetime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
    ui->client_rec->append(datetime);
    if(ui->HEXDisp->checkState() != Qt::Checked)
    {
        ui->client_rec->append(message);
    }
    else
    {
        ui->client_rec->append(message.toLocal8Bit().toHex(' '));
    }
}
void WebSocketApply::C_reciveBinary(const QByteArray& message)
{
    QString datetime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
    ui->client_rec->append(datetime);

    ui->client_rec->append(message.toHex(' '));
}
void WebSocketApply::C_error(const QString& msg)
{
    QString datetime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
    ui->client_rec->append(datetime);
    ui->client_rec->append(msg);
}
void WebSocketApply::C_connection(const QString& msg, const bool state)
{
    QString datetime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
    ui->client_rec->append(datetime);
    ui->client_rec->append(msg);
    if(state)
    {
        ui->client_connect->setEnabled(false);
        ui->client_disconnect->setEnabled(true);
    }
    else
    {
        ui->client_connect->setEnabled(true);
        ui->client_disconnect->setEnabled(false);
    }
}
void WebSocketApply::on_client_connect_clicked()
{
    emit C_connect(ui->ServerUrl->text());
    ui->client_connect->setEnabled(false);
    ui->client_disconnect->setEnabled(true);
    ui->client_send->setEnabled(true);
}

void WebSocketApply::on_client_disconnect_clicked()
{
    emit C_disconnect();
    ui->client_connect->setEnabled(true);
    ui->client_disconnect->setEnabled(false);
    ui->client_send->setEnabled(false);
}

void WebSocketApply::on_client_send_clicked()
{
    QString msg = ui->client_msg->toPlainText();
    if(ui->SendN->isChecked())
        msg.append('\n');
    if(ui->HEXSend->isChecked())    //发送16进制
    {
        emit C_sendBinary(QByteArray::fromHex(msg.toUtf8()));
        return;
    }
    emit C_send(msg);
}

void WebSocketApply::on_Cclear_clicked()
{
    ui->client_rec->clear();
}
/* 客户端操作 end */

/* 服务端操作 begin */
void WebSocketApply::S_recive(const QString& ClientInfo, const QString& message)
{
    QString datetime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
    ui->server_rec->append(datetime + "  " + ClientInfo);
    if(ui->HEXDisp->checkState() != Qt::Checked)
    {
        ui->server_rec->append(message);
    }
    else
    {
        ui->server_rec->append(message.toLocal8Bit().toHex(' '));
    }
}
void WebSocketApply::S_reciveBinary(const QString& ClientInfo, const QByteArray& message)
{
    QString datetime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
    ui->server_rec->append(datetime + "  " + ClientInfo);
    ui->server_rec->append(message.toHex(' '));
}
void WebSocketApply::add_client(const QString& ClientInfo)
{
    QString datetime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
    ui->server_rec->append(datetime);
    ui->server_rec->append("New client " + ClientInfo + " join in.");

    ui->clients_list->addItem(ClientInfo);
}

void WebSocketApply::remove_client(const QString& ClientInfo)
{
    QString datetime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
    ui->server_rec->append(datetime);
    ui->server_rec->append("Client " + ClientInfo + " leave.");

    ui->clients_list->takeItem(ui->clients_list->row( ui->clients_list->findItems(ClientInfo, Qt::MatchFixedString|Qt::MatchCaseSensitive).at(0)));
}

void WebSocketApply::S_error(const QString& error_message)
{
    QString datetime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
    ui->server_rec->append(datetime);
    ui->server_rec->append(error_message);
}
void WebSocketApply::on_Sclear_clicked()
{
    ui->server_rec->clear();
}

void WebSocketApply::on_server_start_clicked()
{
    emit S_start(ui->listen_address->currentText(), ui->listen_port->text().toInt());
    ui->server_start->setEnabled(false);
    ui->server_stop->setEnabled(true);
    ui->kick->setEnabled(true);
    ui->server_send->setEnabled(true);
}

void WebSocketApply::on_server_stop_clicked()
{
    emit S_stop();
    ui->server_start->setEnabled(true);
    ui->server_stop->setEnabled(false);
    ui->kick->setEnabled(false);
    ui->server_send->setEnabled(false);
//    ui->clients_list->clear();
}

void WebSocketApply::on_server_send_clicked()
{
    QString msg = ui->server_msg->toPlainText();
    if(ui->SendN->isChecked())
        msg.append('\n');

    if(ui->clients_list->currentRow() != -1)
    {
        if(ui->HEXSend->isChecked())
        {
            emit S_sendBinary(ui->clients_list->currentItem()->text(),
                              QByteArray::fromHex(msg.toUtf8()),
                              ui->checkBox->checkState()
                              );
            return;
        }
        emit S_send(ui->clients_list->currentItem()->text(),
                    msg,
                    ui->checkBox->checkState()
                    );
        return;
    }
    if(ui->checkBox->checkState() == Qt::Checked)//to all
    {
        int count = ui->clients_list->count();
        if(ui->HEXSend->isChecked())
        {
            QByteArray Bmsg = QByteArray::fromHex(msg.toUtf8());
            for(int index = 0; index < count; index++)
            {
                emit S_sendBinary(ui->clients_list->item(index)->text(),
                            Bmsg,
                            ui->checkBox->checkState()
                            );
            }
            return;
        }
        for(int index = 0; index < count; index++)
        {
            emit S_send(ui->clients_list->item(index)->text(),
                        msg,
                        ui->checkBox->checkState()
                        );
        }
        return;
    }
    QMessageBox::information(this,"提示","未选择客户端！");
}

void WebSocketApply::on_kick_clicked()
{
    if(ui->clients_list->currentRow() >= 0)
    {
        //通知服务端移除所选客户端
        emit S_remove(ui->clients_list->currentItem()->text());
        //界面上客户端列表移除所选客户端
        ui->clients_list->takeItem(ui->clients_list->row(ui->clients_list->currentItem()));
    }

}

/* 服务端操作 end */

void WebSocketApply::on_act_About_triggered()
{
    QMessageBox::information(this,"关于","预设\n1、NonSecureMode\n2、服务端监听所有地址\n3、服务端口可自行修改\n4、作者：香菇滑稽blog.csdn.net/wwplh5520370");
}

void WebSocketApply::on_SLoopSend_stateChanged(int arg1)
{
    if(arg1 == Qt::Checked)
    {
        if(ui->SendCycle->text().toInt() <= 0)
        {
            QMessageBox::information(this,"提示","发送周期必须大于0！");
            return;
        }
        if(ui->clients_list->currentRow()<0 && !ui->checkBox->isChecked())
        {
            QMessageBox::information(this,"提示","未选择客户端！");
            return;
        }
        STimer->start(ui->SendCycle->text().toInt());
    }
    else
    {
        STimer->stop();
    }
}

void WebSocketApply::on_CLoopSend_stateChanged(int arg1)
{
    if(arg1 == Qt::Checked)
    {
        if(ui->SendCycle->text().toInt() <= 0)
        {
            QMessageBox::information(this,"提示","发送周期必须大于0！");
            return;
        }
        CTimer->start(ui->SendCycle->text().toInt());
    }
    else
    {
        CTimer->stop();
    }
}
